#pragma once

#include <vector>
#include <typelib/types.h>
#include "type_traits.h"

namespace outline {

typedef unsigned int uint;
typedef std::vector<uint> uint_vector;
typedef std::vector<uint> index_vector_type;

/// type of junction between bezier pieces
enum junc_type {
	junc_cusp,		///< most general case
	junc_smooth,	///< node point and two control points lie on a single line
	junc_smooth_affine, ///< affine-invariant version of node: relative lengths of tangent is fixed
	junc_symmetrical,///< same as smooth but distances from control points to the node point are equal (both moustaches at a junction must be equal except for a sign)
	junc_flat		///< node point and both control points are coincide
};

inline bool is_smooth_or_symm(junc_type j)
	{ return j == junc_smooth || j == junc_smooth_affine || j == junc_symmetrical; }

uint const degrees_of_freedom[] = {
	3, //junc_cusp
	2, //junc_smooth
	2, //junc_symmetrical
	0, //junc_flat
};

template <class R> 
struct junction {
	junc_type type;
	R l, r; ///< proportions of left and right tangents, ignored for junc_cusp type,
			///< for symmetric junctions: l = -1, r = 1,
			///< for other smooth junctoins at least one of l and r should be not zero
};

enum {
	fixed_left_tan_dir = 1, ///< direction of the left tangent is fixed
	fixed_right_tan_dir = 2 ///< direction of the right tangent is fixed
};

enum fit_mode {
	fit_global,
	fit_local,
	fit_global_then_local
};

enum transform_type {
	translation,
	rigid,
	rigid_scale,
	affine
};

template <class R> 
struct guide_params {
	uint max_iterations;
	R stop_mean_discrepancy;
	R oversample_factor; ///< the ratio between the counts of fitted points on bezier and its length
	uint search_half_window;
public:
	guide_params() { }
	guide_params(uint mi, R s, R o, uint shw) : 
		max_iterations(mi), stop_mean_discrepancy(s), oversample_factor(o), search_half_window(shw) { }
};

template <class R>
struct bezier;

template <typename R>
struct typedefsR
{
	typedef R real_type;
	typedef std::vector<real_type> real_vector_type;
	typedef std::vector<real_vector_type> real_matrix_type;
	typedef point<real_type> real_point_type;
	typedef std::vector<real_point_type> real_point_vector_type;

	typedef bezier<real_type> bezier_type;

	typedef typename type_traits<real_type>::accumulator_type accu_type;
};

template <typename T, typename R = typename type_traits<T>::real_type>
struct typedefs : typedefsR<R>
{
	typedef T node_coord_type;
	typedef point<T> node_type;
	typedef std::vector<node_type> nodes_type;
};

} //namespace outline
